package gbench.sandbox.record;

import org.junit.jupiter.api.Test;

import gbench.common.tree.LittleTree.IRecord;

import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import gbench.common.tree.LittleTree.KVPair;

import static gbench.common.tree.LittleTree.*;
import static gbench.common.tree.LittleTree.IRecord.*;
import static gbench.common.tree.LittleTree.KVPair.*;



/**
 * 
 * @author gbench
 *
 */
public class JunitFlat {
    
    /**
     *  select u.name as uname, p.name as pname, price  <br>
     *  from user u,product p <br>
     *  where u.name = "张三" and p.name = "水蜜桃" <br>
     *  的 IRecord的实现。<br>
     *  实现一个类似于SQL的 SELECT的 语句的功能 
     */
    @Test
    public void foo() {
        final var ub = IRecord.builder("id,name,sex,address"); // user builder
        final var pb = IRecord.builder("id,name,price"); // product builder
        final var users=Stream.of("张三,李四,王五".split(",")).map(kvp())
            .map(i->A(i.key(),i.value(),(i.key()%2),"地址"+i))
            .map(ub::get).toArray(IRecord[]::new);
        final var products=Stream.of("苹果,草莓,水蜜桃".split(",")).map(kvp())
            .map(i->A(i.key(),i.value(),Math.random()*10000))
            .map(pb::get).toArray(IRecord[]::new);
        
        // 变换名称 并 筛选数据
        Elem.cph2(users,products).map(IRecord::L2REC).map(e->e.flat2("u,p")) // users, products 的 笛卡尔积: from user u,product p
        .filter(e->e.str("u.name").equals("张三") && e.str("p.name").equals("水蜜桃")) // 过滤条件: where u.name = "张三" and p.name = "水蜜桃"
        .map(e->e.filter("u.name,p.name,p.price").aoks2rec2("uname,pname,price")) // 列值提取&重命名: select u.name as uname, p.name as pname, price
        .forEach(System.out::println); // 打印输出
    }
    
    /**
     *  select u.name as uname, p.name as pname, price  <br>
     *  from user u,product p <br>
     *  where u.name = "张三" and p.name = "水蜜桃" <br>
     *  的 IRecord的实现。<br>
     *  实现一个类似于SQL的 SELECT的 语句的功能 
     */
    @SuppressWarnings("unchecked")
    @Test
    public void bar() {
        final var ub = IRecord.builder("id,name,sex,address"); // user builder
        final var pb = IRecord.builder("id,name,price"); // product builder
        final var users=Stream.of("张三,李四,王五".split(",")).map(kvp())
            .map(i->A(i.key(),i.value(),(i.key()%2),"地址"+i))
            .map(ub::get).toArray(IRecord[]::new);
        final var products=Stream.of("苹果,草莓,水蜜桃".split(",")).map(kvp())
            .map(i->A(i.key(),i.value(),Math.random()*10000))
            .map(pb::get).toArray(IRecord[]::new);
        final Function<KVPair<Predicate<IRecord>,IRecord[]>,IRecord[]> filter_mapper =  // 过滤映射器。
            kvp -> Stream.of(kvp._2()).filter(kvp._1()).toArray(IRecord[]::new); // filter_mapper
        
        final var prefilterp = REC( // 过滤条件: where u.name = "张三" and p.name = "水蜜桃"
            "u", (Predicate<IRecord>) (e -> e.str("name").equals("张三")),
            "p", (Predicate<IRecord>) (e -> e.str("name").equals("苹果"))
        ); // 前置过滤器
        
        // 变换名称 并 筛选数据
        Elem.cph2( // descartes 积
            A2R( users, products ).keys("u,p") // users, products 的 笛卡尔积: from user u,product p , 这里对 where条件引入提前过滤以降低 笛卡尔积规模，以提高效率
            .stream ( kvp -> // 为 value 增加 前置 过滤器 即  where u.name = "张三" and p.name = "水蜜桃" 
                KVP( (Predicate<IRecord>) prefilterp.get(kvp.key()), (IRecord[]) kvp.value() ) 
            ).filter(e->e._1()!=null).map(filter_mapper).collect(Collectors.toList()) // 归集列表数组。
        ).map(IRecord::L2REC).map(e->e.flat2("u,p")) // users, products 的 笛卡尔积: from user u,product p
        //.filter(e->e.str("u.name").equals("张三") && e.str("p.name").equals("水蜜桃")) // 过滤条件: where u.name = "张三" and p.name = "水蜜桃"
        .map(e->e.filter("u.name,p.name,p.price").aoks2rec2("uname,pname,price")) // 列值提取&重命名: select u.name as uname, p.name as pname, price
        .forEach(System.out::println); // 打印输出
    }
    
    /**
     * flat 的使用方法演示
     */
    @Test
    public void qux() {
        final var r = REC("id",1,"product","苹果","user",REC("name","张三","sex","男"),"address",REC("city","上海","district","长宁区")).flat();
        System.out.println(r);
        // 演示 evaluate 方法
        final var p = KVP((Function<Integer,Integer>)(i->i+1),24).evaluate(Integer.class);
        System.out.println( "kvp evaluate Integer.class:"+p);
    }

}
